#include "myglwidget.h"
#include "tex.h"

myGLWidget::myGLWidget(QWidget *parent,QString filename): QGLWidget(parent)
{
    xRot = yRot = zRot = 0.0;
    triangle_rotate = 0.0;
    facenum=0;
    scalednum=1;
    frameIndex=0;
    offset_x=0;
    offset_y=0;
    offset_z=0;
    weiliNum=0;

    //setGeometry( 10, 30, 800, 600 );
    //this->setWindowTitle(tr("模型显示窗口"));//setCaption(tr("模型显示窗口"));
    myply=new ply(filename);
    //this->pp=myply->getpointhead();
    this->pp=myply->getpoint(0);
    this->face=myply->getpface();
    this->facenum=myply->getfacenum();
    this->pointnum=myply->getpointnum();
}

myGLWidget::~myGLWidget()
{
    delete myply;
    myply=NULL;
}

QSize myGLWidget::minimumSizeHint() const
{
    return QSize(50, 50);
}

QSize myGLWidget::sizeHint() const
{
    return QSize(640, 480);
}

void myGLWidget::initializeGL()
{
//    setGeometry(300, 150, 640, 480);//设置窗口初始位置和大小
    loadGLTextures();
    glEnable(GL_TEXTURE_2D);//允许采用2D纹理技术
    glShadeModel(GL_SMOOTH);//设置阴影平滑模式
    qtPurple = QColor::fromCmykF(0.39, 0.39, 0.0, 0.0);
    qglClearColor(qtPurple.dark()); //set backgroud color
    //glClearColor(0.0, 0.0, 0.0, 0.0);//改变窗口的背景颜色，不过我这里貌似设置后并没有什么效果
    glClearDepth(1.0);//设置深度缓存
    glEnable(GL_DEPTH_TEST);//允许深度测试
    glDepthFunc(GL_LEQUAL);//设置深度测试类型
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//进行透视校正
    /* 这个函数中，我们对 OpenGL 进行所有的设置。我们设置清除屏幕所用的颜色，打开深度缓
    存，启用 smooth shading（阴影平滑） ，等等。这个例程直到 OpenGL 窗口创建之后才会被
    调用。 */
}

void myGLWidget::paintGL()
{
    int texidx;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glClear()函数在这里就是对initializeGL()函数
    //中设置的颜色和缓存深度等起作用
    glLoadIdentity();//重置当前的模型观察矩阵,该句执行完后，将焦点移动到了屏幕的中心
    /*下面几句代码是用来画三角形的,以glBegin()开始，glEnd()结束；glVertex3f为给定一个3维的顶点，坐标值为浮点型*/
    // glTranslatef(-1.5f, 0.0f, -6.0f);//首先移动当前焦点位置
    // glTranslatef(-0.3, 0.3, -0.6);
    // glColor3f(1.0f, 0.0f, 0.0f);
    // glDisable(GL_TEXTURE_2D);
    // glBegin(GL_TRIANGLES);//GL_TRIANGLES代表为画三角形
    // glVertex3f(0.0f, 0.2f, 0.0f);//上顶点坐标
    // glVertex3f(-0.2f, -0.2f, 0.0f);//左下角坐标
    // glVertex3f(0.2f, -0.2f, 0.0f);//右下角坐标
    // glEnd();//结束画完
    if(myply==NULL)
        return ;
    this->pp=myply->getpoint(frameIndex);
    float scaled=myply->getplytop()->none13*2/scalednum;
    glTranslatef(offset_x,offset_y, offset_z);
    glRotatef(xRot / 16.0, 1.0, 0.0, 0.0);
    glRotatef(yRot / 16.0, 0.0, 1.0, 0.0);
    glRotatef(zRot / 16.0, 0.0, 0.0, 1.0);

    if(facenum>0)
        for(int i=0;i<facenum;i++){
            texidx = myply->getTexIndex(i);
            //qDebug("%d, %d, %d, weiliNum %d", i, texidx, texture[texidx], weiliNum);
            if((texture[texidx]>0) && ((int)texture[texidx]<=weiliNum))
                glBindTexture(GL_TEXTURE_2D, texture[texidx]);
            else
                glBindTexture(GL_TEXTURE_2D, 0);
            glBegin(GL_TRIANGLES);
            glTexCoord2f(pp[face[i].index1].U,pp[face[i].index1].V );
            glVertex3f(pp[face[i].index1].x/scaled,pp[face[i].index1].y/scaled,pp[face[i].index1].z/scaled);//上顶点坐标
            glTexCoord2f(pp[face[i].index2].U,pp[face[i].index2].V );
            glVertex3f(pp[face[i].index2].x/scaled,pp[face[i].index2].y/scaled,pp[face[i].index2].z/scaled);//左下角坐标
            glTexCoord2f(pp[face[i].index3].U,pp[face[i].index3].V );
            glVertex3f(pp[face[i].index3].x/scaled,pp[face[i].index3].y/scaled,pp[face[i].index3].z/scaled);//右下角坐标
            glEnd();
        }
}

void myGLWidget::timerEvent(QTimerEvent *event)
{
    triangle_rotate += 0.05;  //为了看到动态效果，这里每次刷新后旋转的角度都加0.05
    xRot = 0.1;
    yRot = 0.1;
    zRot = 0.1;
    update();
}

void myGLWidget::resizeGL( int width, int height )
{
    if (0 == height){ //防止 height为 0。
        height = 1;
    }
    glViewport( 0, 0, (GLint)width, (GLint)height );  //重置当前的视口（Viewport） 。
    glMatrixMode( GL_PROJECTION ); //选择投影矩阵。
    glLoadIdentity(); //重置投影矩阵。
    //gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 ); //建立透视投影矩阵。
    glMatrixMode( GL_MODELVIEW );   //选择模型观察矩阵。
    glLoadIdentity();    //重置模型观察矩阵。
}

static void qNormalizeAngle(int &angle)
{
    while (angle < 0)
        angle += 360 * 16;
    while (angle > 360 * 16)
        angle -= 360 * 16;
}

void myGLWidget::setXRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != xRot) {
        xRot = angle;
        emit xRotationChanged(angle);
        update();
    }
}

void myGLWidget::setYRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != yRot) {
        yRot = angle;
        emit yRotationChanged(angle);
        update();
    }
}

void myGLWidget::setZRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != zRot) {
        zRot = angle;
        emit zRotationChanged(angle);
        update();
    }
}

void myGLWidget::mousePressEvent(QMouseEvent *event)
{
    lastPos = event->pos();
}

void myGLWidget::mouseMoveEvent(QMouseEvent *event)
{
    int dx = event->x() - lastPos.x();
    int dy = event->y() - lastPos.y();

    if (event->buttons() & Qt::LeftButton) {
        setXRotation(xRot + 8 * dy);
        setYRotation(yRot + 8 * dx);
    } else if (event->buttons() & Qt::RightButton) {
        setXRotation(xRot + 8 * dy);
        setZRotation(zRot + 8 * dx);
    }
    lastPos = event->pos();
}

void myGLWidget::wheelEvent(QWheelEvent *e)
{
    GLfloat zValue = e->delta();
    if(zValue>0)
        scalednum += 0.1;
    else
        scalednum -= 0.1;
    if(scalednum <= 0)
        scalednum = 0;
    update();
}

void myGLWidget::loadGLTextures()
{
    QImage  buf;
    QString texfilename;
    QString savefilename;
    //QPixmap *pixmap;
    GLint last_texture_ID;
    weiliNum=0;
    qDebug("myply->getwenlinum() %d\n", myply->getwenlinum());
    for(int i=0;i<myply->getwenlinum();i++){
        if(myply->getpwenli()[i].texnum>=0){
            QString aa=texDir;
            texfilename=aa+texfilename.sprintf("\\ALL%05d.TEX",myply->getpwenli()[i].texnum);
            std::string str = texfilename.toStdString();
            qDebug("load tex file [%s]\n", str.c_str());
            tex mytex(texfilename);
            buf=QImage((unsigned char *)mytex.getBmpDataH(),mytex.getWidth(),mytex.getHeight(),QImage::Format_RGB555);
            //pixmap = new QPixmap(320, 240);
           //*pixmap = QPixmap::fromImage(buf.scaled(320, 240));
            //savefilename=savefilename.sprintf("%05d.bmp",myply->getpwenli()[i].texnum);
            //str = savefilename.toStdString();
            //qDebug("save file [%s]\n", str.c_str());
            //pixmap->save(savefilename);
           // QMatrix matrix;
           // matrix.rotate(180);
            //buf = buf.transformed(matrix);
            if(buf.isNull()){
                qWarning("Cannot open the image...");
                QImage dummy(128, 128, QImage::Format_RGB32);//当没找到所需打开的图片时，创建一副128*128大小，深度为32位的位图
                dummy.fill(Qt::green);
                buf = dummy;
            }
            texImage[i] = convertToGLFormat(buf);//将Qt图片的格式buf转换成opengl的图片格式tex
            glGenTextures(1, &texture[i]);//开辟一个纹理内存，内存指向texture[0]
            glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);
            //qDebug("gen Textures %d, last id %d", texture[i], last_texture_ID);
            glBindTexture(GL_TEXTURE_2D, texture[i]);//将创建的纹理内存指向的内容绑定到纹理对象GL_TEXTURE_2D上，经过这句代码后，以后对
            //GL_TEXTURE_2D的操作的任何操作都同时对应与它所绑定的纹理对象
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//当所显示的纹理比加载进来的纹理小时，采用GL_LINEAR的方法来处理
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//当所显示的纹理比加载进来的纹理大时，采用GL_LINEAR的方法来处理
            glTexImage2D(GL_TEXTURE_2D, 0, 3, texImage[i].width(), texImage[i].height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage[i].bits());//开始真正创建纹理数据
            weiliNum++;
            glBindTexture(GL_TEXTURE_2D, last_texture_ID);
        }
    }
}

